using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Text;
using OracleInternal.Common;
using OracleInternal.SqlAndPlsqlParser.LocalParsing;
using OracleInternal.SqlAndPlsqlParser.RuleProcessors;

namespace OracleInternal.SqlAndPlsqlParser
{
	public class OracleLpParser
	{
		private OracleSqlEarley m_vParser;

		private OracleMbEarleySqlPlsqlRuleProcessorTableDictionary m_vRulesProcessorTableDictionary;

		internal OracleLpParser(OracleMbEarleySqlPlsqlRuleProcessorTableDictionary rulesProcessorTableDictionary)
		{
			m_vRulesProcessorTableDictionary = rulesProcessorTableDictionary;
			m_vParser = new OracleSqlEarley(m_vRulesProcessorTableDictionary.Grammar);
		}

		public OracleLpParser(int type = 0)
			: this((type == 0) ? OracleMbEarleySqlPlsqlAnsiRuleProcessorTableDictionary.Instance : OracleMbEarleySqlPlsqlRuleProcessorTableDictionary.Instance)
		{
		}

		public string TestParse(string s)
		{
			ParseNode parseNode = null;
			List<LexerToken> list = null;
			StringBuilder stringBuilder = null;
			try
			{
				using (new PerformanceTimer("Lexing"))
				{
					list = LexerToken.Parse(s);
				}
				using (new PerformanceTimer("Parsing"))
				{
					parseNode = m_vParser.Parse(s, list);
				}
				if (parseNode != null)
				{
					return parseNode.ToString(m_vParser.EarleyGrammar);
				}
				stringBuilder = new StringBuilder("Parse failed\n");
			}
			catch (ParserException ex)
			{
				stringBuilder = new StringBuilder(ex.Message);
			}
			int num = 0;
			stringBuilder.Append("\nTokenizer output:\n =========================\n");
			if (list != null)
			{
				foreach (LexerToken item in list)
				{
					stringBuilder.Append(item.ToString());
					stringBuilder.Append('\n');
					if (num++ == 200)
					{
						stringBuilder.Append($"... {list.Count - 200} more tokens not printed\n");
						break;
					}
				}
			}
			return stringBuilder.ToString();
		}

		public IEnumerable<OracleLpStatement> ParseStatements(IOracleMetadata md, string s)
		{
			ParseNode parseNode = null;
			List<LexerToken> list = null;
			using (new PerformanceTimer("Lexing"))
			{
				list = LexerToken.Parse(s);
			}
			using (new PerformanceTimer("Parsing"))
			{
				parseNode = m_vParser.Parse(s, list);
			}
			using (new PerformanceTimer("Statement information retrieval"))
			{
				if (parseNode != null)
				{
					OracleLpParserContext oracleLpParserContext = new OracleLpParserContext(m_vParser, m_vRulesProcessorTableDictionary);
					oracleLpParserContext.SetActiveObject(0, md);
					oracleLpParserContext.Script = s;
					oracleLpParserContext.Tokens = list;
					oracleLpParserContext.RootParseNode = parseNode;
					oracleLpParserContext.CurrentParseNode = parseNode;
					oracleLpParserContext.PropertiesBag.DefaultSchemaName = "";
					OracleMbEarleyRuleMultiProcessor.ProcessNodeRules(parseNode, oracleLpParserContext.CurrentRuleIndex, -1, oracleLpParserContext);
					ReadOnlyCollection<OracleLpStatement> statements = oracleLpParserContext.Statements;
					oracleLpParserContext.Clear();
					return statements;
				}
				return null;
			}
		}
	}
}
